package com.reverse.engineering.util.core.run.util;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import com.ApplicationProperties;
import com.reverse.engineering.util.core.run.bean.DatabaseProperties;
import com.reverse.engineering.util.core.run.bean.database.Database;
import com.reverse.engineering.util.core.run.bean.database.Field;
import com.reverse.engineering.util.core.run.bean.database.Table;
import com.reverse.engineering.util.core.run.bean.java.File;
import com.reverse.engineering.util.core.run.bean.java.FileFeild;
import com.reverse.engineering.util.core.run.bean.java.FileProperties;
import com.reverse.engineering.util.core.run.constant.Constant;
import com.reverse.engineering.util.core.run.enums.FieldEquals;
import com.reverse.engineering.util.core.run.enums.FileGenerate;

/**
 * 初始化动态数据类
 * 
 * @author liu
 * @date 2020-08-20
 */
public class InitProperties {

    /**
     * 初始化属性
     * 
     * @throws IOException
     */
    public static void initProperties() throws IOException {

        initPackageNameAndPath();
        File.databaseNameY = Database.databaseName;
        File.databaseNameD = File.databaseNameY.toUpperCase();
        File.databaseCollate = DatabaseProperties.getDatabaseCollate();
        File.databaseCharacter = DatabaseProperties.getDatabaseCharacter();

        ArrayList<FileProperties> fileproperties = File.fileProperties;
        for (Table table : Database.tables) {
            fileproperties.add(initProperties(table));
        }

    }

    /**
     * 初始化属性
     * 
     * @throws IOException
     */
    public static FileProperties initProperties(Table table) throws IOException {
        FileProperties fileProperties = new FileProperties();

        // 初始化属性
        fileProperties.setEntityClassNameD(getEntityClassNameD(table.getTableName()));
        fileProperties.setEntityClassNameX(toLowerCase(fileProperties.getEntityClassNameD()));
        fileProperties.setEntityParamNameD(getEntityParamNameD(table.getTableName()));
        fileProperties.setEntityParamNameX(toLowerCase(fileProperties.getEntityParamNameD()));
        fileProperties.setEntityBeanName(getBeanName(fileProperties.getEntityClassNameD()));
        fileProperties.setDaoInterfaceClassNameD(getDapInterfaceNameD(table.getTableName()));
        fileProperties.setDaoInterfaceClassNameX(toLowerCase(fileProperties.getDaoInterfaceClassNameD()));
        fileProperties.setDaoInterfaceParamNameD(getDapInterfaceParamNameD(table.getTableName()));
        fileProperties.setDaoInterfaceParamNameX(toLowerCase(fileProperties.getDaoInterfaceParamNameD()));
        fileProperties.setDaoInterfaceBeanName(getBeanName(fileProperties.getDaoInterfaceClassNameD()));
        fileProperties.setDaoImplClassNameD(getDapImplClassNameD(table.getTableName()));
        fileProperties.setDaoImplClassNameX(toLowerCase(fileProperties.getDaoImplClassNameD()));
        fileProperties.setDaoImplParamNameD(getDapImplClassParamNameD(table.getTableName()));
        fileProperties.setDaoImplParamNameX(toLowerCase(fileProperties.getDaoImplParamNameD()));
        fileProperties.setDaoImplBeanName(getBeanName(fileProperties.getDaoImplClassNameD()));
        fileProperties.setServiceInterfaceClassNameD(getServiceInterfaceNameD(table.getTableName()));
        fileProperties.setServiceInterfaceClassNameX(toLowerCase(fileProperties.getServiceInterfaceClassNameD()));
        fileProperties.setServiceInterfaceParamNameD(getServiceInterfaceParamNameD(table.getTableName()));
        fileProperties.setServiceInterfaceParamNameX(toLowerCase(fileProperties.getServiceInterfaceParamNameD()));
        fileProperties.setServiceInterfaceBeanName(getBeanName(fileProperties.getServiceInterfaceClassNameD()));
        fileProperties.setServiceImplClassNameD(getServiceImplClassNameD(table.getTableName()));
        fileProperties.setServiceImplClassNameX(toLowerCase(fileProperties.getServiceImplClassNameD()));
        fileProperties.setServiceImplParamNameD(getServiceImplClassParamNameD(table.getTableName()));
        fileProperties.setServiceImplParamNameX(toLowerCase(fileProperties.getServiceImplParamNameD()));
        fileProperties.setServiceImplBeanName(getBeanName(fileProperties.getServiceImplClassNameD()));
        fileProperties.setControllerImplClassNameD(getControllerImplClassNameD(table.getTableName()));
        fileProperties.setControllerImplClassNameX(toLowerCase(fileProperties.getControllerImplClassNameD()));
        fileProperties.setControllerImplParamNameD(getControllerImplClassParamNameD(table.getTableName()));
        fileProperties.setControllerImplParamNameX(toLowerCase(fileProperties.getControllerImplParamNameD()));
        fileProperties.setControllerImplBeanName(getBeanName(fileProperties.getControllerImplClassNameD()));
        fileProperties.setControllerMapping(getControllerMappingX(table.getTableName()));
        fileProperties.setXmlName(getXmlName(table.getTableName()));
        fileProperties.setSqlName(getSqlName(ApplicationProperties.sqlName));

        fileProperties.setClassComment(table.getTableComment() != null ? table.getTableComment() : "");
        fileProperties.setSerialVersionUID(System.currentTimeMillis() + "L");
        fileProperties.setClassCommentDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        fileProperties.setExistId(table.getExistId());
        if (fileProperties.getExistId()) {
            fileProperties.setDatabaseIdName(table.getIdName());
            if (null != fileProperties.getDatabaseIdName()) {
                fileProperties.setDatabaseIdNameD(fileProperties.getDatabaseIdName().toUpperCase());
                fileProperties.setJavaIdNameD(toUpperCase(enableFieldMapUnderscoreToCamelCase(table.getIdName())));
                fileProperties.setJavaIdNameX(toLowerCase(fileProperties.getJavaIdNameD()));
                if (StringUtils.isBlank(fileProperties.getXing())) {
                    fileProperties.setXing(fileProperties.getDatabaseIdName());
                    fileProperties.setXingD(fileProperties.getDatabaseIdNameD());
                }
            }
        }
        fileProperties.setExistSerialNumber(table.getExistSerialNumber());
        if (fileProperties.getExistSerialNumber()) {
            fileProperties.setDatabaseSerialNumberName(table.getSerialNumberName());
            if (null != fileProperties.getDatabaseSerialNumberName()) {
                fileProperties.setDatabaseSerialNumberNameD(fileProperties.getDatabaseSerialNumberName().toUpperCase());
                fileProperties.setJavaSerialNumberNameD(
                    toUpperCase(enableFieldMapUnderscoreToCamelCase(table.getSerialNumberName())));
                fileProperties.setJavaSerialNumberNameX(toLowerCase(fileProperties.getJavaSerialNumberNameD()));
                if (StringUtils.isBlank(fileProperties.getXing())) {
                    fileProperties.setXing(fileProperties.getDatabaseSerialNumberName());
                    fileProperties.setXingD(fileProperties.getDatabaseSerialNumberNameD());
                }
            }
        }
        fileProperties.setExistDel(table.getExistDel());
        if (fileProperties.getExistDel()) {
            fileProperties.setDatabaseDelName(table.getDelName());
            if (null != fileProperties.getDatabaseDelName()) {
                fileProperties.setDatabaseDelNameD(fileProperties.getDatabaseDelName().toUpperCase());
                fileProperties.setJavaDelNameD(toUpperCase(enableFieldMapUnderscoreToCamelCase(table.getDelName())));
                fileProperties.setJavaDelNameX(toLowerCase(fileProperties.getJavaDelNameD()));
                if (StringUtils.isBlank(fileProperties.getXing())) {
                    fileProperties.setXing(fileProperties.getDatabaseDelName());
                    fileProperties.setXingD(fileProperties.getDatabaseDelNameD());
                }
            }
        }
        int length = ApplicationProperties.DEL_NUMBER_LIST.length;
        if (ApplicationProperties.DEL_NUMBER_LIST != null && length > 0) {
            StringBuilder stringBuilder = new StringBuilder();
            int[] delNumberList = ApplicationProperties.DEL_NUMBER_LIST;
            if (length == 2) {
                int number = ApplicationProperties.DEL_NUMBER;
                int one = delNumberList[0];
                int two = delNumberList[1];
                if (one != number) {
                    number = one;
                    stringBuilder.append("= ").append(number);
                } else if (two != number) {
                    number = two;
                    stringBuilder.append("= ").append(number);
                } else {
                    stringBuilder.append("!= ").append(number);
                }
            } else {
                stringBuilder.append("IN (");
                for (int i : delNumberList) {
                    if (i != ApplicationProperties.DEL_NUMBER) {
                        stringBuilder.append(i).append(",");
                    }
                }
                if (stringBuilder.indexOf("(") == stringBuilder.length() - 1) {
                    stringBuilder = new StringBuilder("!= ").append(ApplicationProperties.DEL_NUMBER);
                } else {
                    String substring = stringBuilder.substring(0, stringBuilder.length() - 1);
                    stringBuilder = new StringBuilder(substring + ")");
                }
            }
            fileProperties.setDelNumberList(stringBuilder.toString());
        } else {
            // 给个空字符串防止空指针
            fileProperties.setDelNumberList("");
        }
        fileProperties.setAutoIncrementSql(table.getAutoIncrementSql());
        fileProperties.setTableName(getTableName(table.getTableName()));
        fileProperties.setTableNameD(fileProperties.getTableName().toUpperCase());
        fileProperties.setTableStatic(table.getTableStatic());
        fileProperties.setOperation(table.getOperation());

        for (Field field : table.getFields()) {
            initFieldAndMethod(field, fileProperties, table);
        }

        return fileProperties;
    }

    /**
     * 获取表名
     * 
     * @param tableName
     * @return
     */
    private static String getTableName(String tableName) {
        if (ApplicationProperties.databasePrefix) {
            return ApplicationProperties.databaseTablePrefix + tableName + ApplicationProperties.databaseTableSuffix;
        }
        return tableName;
    }

    /**
     * 初始化字段和方法
     * 
     * @param field
     * @param table
     * @param fileProperties
     * @param table 
     */
    private static void initFieldAndMethod(Field field, FileProperties fileProperties, Table table) {
        ArrayList<FileFeild> fileFeilds = fileProperties.getFileFeild();
        FileFeild fileFeild = new FileFeild();
        fileFeilds.add(fileFeild);

        // 初始化字段
        if (table.getExistAutoIncrement() && !fileProperties.getExistAutoIncrement()
            && field.getFieldProperty() != null) {
            for (String fieldProperty : field.getFieldProperty()) {
                if (fieldProperty.equals("primary key")) {
                    fileProperties.setExistAutoIncrement(true);
                }
            }
        }
        fileFeild.setFieldEquals(field.getFieldEquals());
        fileFeild.setFieldComment(field.getFieldComment());
        fileFeild.setFieldNameD(toUpperCase(enableFieldMapUnderscoreToCamelCase(field.getFieldName())));
        fileFeild.setFieldNameX(toLowerCase(fileFeild.getFieldNameD()));
        fileFeild.setFieldNameDatabase(field.getFieldName());
        fileFeild.setFieldNameDatabaseD(fileFeild.getFieldNameDatabase().toUpperCase());
        fileFeild.setFieldLength(field.getFieldLength());
        fileFeild.setFieldProperty(field.getFieldProperty());
        fileFeild.setReferencesTable(field.getReferencesTable());
        fileFeild.setReferencesField(field.getReferencesField());
        fileFeild.setReferencesComment(field.getReferencesComment());
        fileFeild.setOperation(field.getOperation());
        if (StringUtils.isBlank(fileProperties.getXing())) {
            fileProperties.setXing(fileFeild.getFieldNameDatabase());
            fileProperties.setXingD(fileFeild.getFieldNameDatabaseD());
        }

        // 遍历查询字段对应的类型
        for (FieldEquals fieldEquals : Constant.fieldEquals) {
            if (null != fieldEquals.getDatabase()) {
                if (fieldEquals.getDatabase().equalsIgnoreCase(field.getFieldType())) {
                    fileFeild.setFieldDatabaseType(fieldEquals.getDatabase());
                    fileFeild.setFieldJavaType(fieldEquals.getJava());
                    fileFeild.setFieldXmlType(fieldEquals.getXml());
                    fileFeild.setFieldXmlParamType(fieldEquals.getXmlParam());
                    break;
                }
            }
        }
        if (fileProperties.getExistId() && fileProperties.getXmlIdType() == null) {
            if (fileProperties.getDatabaseIdName().equals(field.getFieldName())) {
                fileProperties.setXmlIdType(fileFeild.getFieldXmlType());
                fileProperties.setXmlIdParamType(fileFeild.getFieldXmlParamType());
                fileProperties.setJavaIdComment(fileFeild.getFieldComment());
                fileProperties.setJavaIdType(fileFeild.getFieldJavaType());
            }
        }
        if (fileProperties.getExistSerialNumber() && fileProperties.getXmlSerialNumberType() == null) {
            if (fileProperties.getDatabaseSerialNumberName().equals(field.getFieldName())) {
                fileProperties.setXmlSerialNumberType(fileFeild.getFieldXmlType());
                fileProperties.setXmlSerialNumberParamType(fileFeild.getFieldXmlParamType());
                fileProperties.setJavaSerialNumberComment(fileFeild.getFieldComment());
                fileProperties.setJavaSerialNumberType(fileFeild.getFieldJavaType());
            }
        }
        if (fileProperties.getExistDel() && fileProperties.getXmlDelType() == null) {
            if (fileProperties.getDatabaseDelName().equals(field.getFieldName())) {
                fileProperties.setXmlDelType(fileFeild.getFieldXmlType());
                fileProperties.setXmlDelParamType(fileFeild.getFieldXmlParamType());
                fileProperties.setJavaDelComment(fileFeild.getFieldComment());
                fileProperties.setJavaDelType(fileFeild.getFieldJavaType());
            }
        }

    }

    /**
     * 初始化包名和文件生成路径
     * 
     * @return
     */
    public static void initPackageNameAndPath() {
        FileGenerate[] values = FileGenerate.values();
        for (FileGenerate fileGenerate : values) {
            fileGenerate.setPackageName(initPackageName(fileGenerate.getBasePath()));
            fileGenerate.setGeneratePath(
                StringUtils.isNotBlank(fileGenerate.getBasePath()) ? fileGenerate.getBasePath() + "/" : "");
        }
    }

    /**
     * 初始化包名
     * 
     * @return
     */
    public static String initPackageName(String path) {
        String one = ":/";
        int indexOf = path.indexOf(one);
        if (indexOf != -1) {
            path = path.substring(indexOf + one.length());
        }
        return path.replace("/", ".");
    }

    /**
     * 字段名驼峰命名转换
     * 
     * @return
     */
    public static String enableFieldMapUnderscoreToCamelCase(String name) {
        StringBuilder stringBuilder = new StringBuilder();
        if (ApplicationProperties.enableFieldMapUnderscoreToCamelCase) {
            String[] split = name.split("_");
            stringBuilder.append(split[0]);
            for (int i = 1; i < split.length; i++) {
                String string = split[i];
                if (string.length() > 0) {
                    stringBuilder.append(toUpperCase(split[i]));
                } else {
                    continue;
                }
            }
        } else {
            stringBuilder.append(name);
        }
        return stringBuilder.toString();
    }

    /**
     * 将单词首字母转为大写
     * 
     * @return
     */
    public static String toUpperCase(String name) {
        StringBuilder stringBuilder = new StringBuilder();
        if (name.length() > 0) {
            stringBuilder.append(name.substring(0, 1).toUpperCase());
            if (name.length() > 1) {
                stringBuilder.append(name.substring(1, name.length()));
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 将单词首字母转为小写
     * 
     * @return
     */
    public static String toLowerCase(String name) {
        StringBuilder stringBuilder = new StringBuilder();
        if (name.length() > 0) {
            stringBuilder.append(name.substring(0, 1).toLowerCase());
            if (name.length() > 1) {
                stringBuilder.append(name.substring(1, name.length()));
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 类名驼峰命名转换
     * 
     * @return
     */
    public static String enableClassMapUnderscoreToCamelCase(String name) {
        StringBuilder stringBuilder = new StringBuilder();
        if (ApplicationProperties.enableClassMapUnderscoreToCamelCase) {
            String[] split = name.split("_");
            stringBuilder.append(split[0]);
            for (int i = 1; i < split.length; i++) {
                String string = split[i];
                if (string.length() > 0) {
                    stringBuilder.append(toUpperCase(split[i]));
                } else {
                    continue;
                }
            }
        } else {
            stringBuilder.append(name);
        }
        return stringBuilder.toString();
    }

    /**
     * 获取类名
     * 
     * @param name
     * @return
     */
    public static String getClassNameD(String name, boolean prefix, String classSuffix) {
        // 有前缀首字母大写,没有前缀首字母小写
        if (ApplicationProperties.databaseTablePrefix != null
            && ApplicationProperties.databaseTablePrefix.trim().length() > 0) {
            name = toUpperCase(name);
        } else {
            name = toLowerCase(name);
        }
        return toUpperCase(enableClassMapUnderscoreToCamelCase(
            new StringBuilder(prefix ? ApplicationProperties.databaseTablePrefix : "").append(name)
                .append(prefix ? ApplicationProperties.databaseTableSuffix : "").append(classSuffix).toString()));
    }

    /**
     * 获取Entity类名(大写)
     * 
     * @param name
     * @return
     */
    public static String getEntityClassNameD(String name) {
        return getClassNameD(name, ApplicationProperties.entityPrefix, "");
    }

    /**
     * 获取Entity的参数名(大写)
     * 
     * @param name
     * @return
     */
    public static String getEntityParamNameD(String name) {
        return getClassNameD(name, ApplicationProperties.paramEnablePrefix, "");
    }

    /**
     * 获取Dao接口名(大写)
     * 
     * @param name
     * @return
     */
    public static String getDapInterfaceNameD(String name) {
        return getClassNameD(name, ApplicationProperties.daoInterfacePrefix, "Dao");
    }

    /**
     * 获取Dao接口的参数名(大写)
     * 
     * @param name
     * @return
     */
    public static String getDapInterfaceParamNameD(String name) {
        return getClassNameD(name, ApplicationProperties.paramEnablePrefix, "Dao");
    }

    /**
     * 获取Bean对象名(如果以两个或以上的大写字母开头就是原类名,否则是首字母小写)
     * 
     * @param tableName
     * @return
     */
    private static String getBeanName(String name) {
        char one = name.charAt(0);
        char two = name.charAt(1);
        if ('A' <= one && one <= 'Z' && 'A' <= two && two <= 'Z') {
            return name;
        }
        return toLowerCase(name);
    }

    /**
     * 获取Dao实现类名(大写)
     * 
     * @param name
     * @return
     */
    public static String getDapImplClassNameD(String name) {
        return getClassNameD(name, ApplicationProperties.daoImplPrefix, "DaoImpl");
    }

    /**
     * 获取Dao实现类的参数名(大写)
     * 
     * @param name
     * @return
     */
    public static String getDapImplClassParamNameD(String name) {
        return getClassNameD(name, ApplicationProperties.paramEnablePrefix, "DaoImpl");
    }

    /**
     * 获取Service接口名(大写)
     * 
     * @param name
     * @return
     */
    public static String getServiceInterfaceNameD(String name) {
        return getClassNameD(name, ApplicationProperties.serviceInterfacePrefix, "Service");
    }

    /**
     * 获取Service接口的参数名(大写)
     * 
     * @param name
     * @return
     */
    public static String getServiceInterfaceParamNameD(String name) {
        return getClassNameD(name, ApplicationProperties.paramEnablePrefix, "Service");
    }

    /**
     * 获取Service实现类名(大写)
     * 
     * @param name
     * @return
     */
    public static String getServiceImplClassNameD(String name) {
        return getClassNameD(name, ApplicationProperties.serviceImplPrefix, "ServiceImpl");
    }

    /**
     * 获取Service实现类的参数名(大写)
     * 
     * @param name
     * @return
     */
    public static String getServiceImplClassParamNameD(String name) {
        return getClassNameD(name, ApplicationProperties.paramEnablePrefix, "ServiceImpl");
    }

    /**
     * 获取Controller实现类名(大写)
     * 
     * @param name
     * @return
     */
    public static String getControllerImplClassNameD(String name) {
        return getClassNameD(name, ApplicationProperties.controllerImplPrefix, "Controller");
    }

    /**
     * 获取Controller实现类的参数名(大写)
     * 
     * @param name
     * @return
     */
    public static String getControllerImplClassParamNameD(String name) {
        return getClassNameD(name, ApplicationProperties.paramEnablePrefix, "Controller");
    }

    /**
     * 获取Controller访问路径(大写)
     * 
     * @param name
     * @return
     */
    public static String getControllerMappingD(String name) {
        return getClassNameD(name, ApplicationProperties.controllerMappingPrefix, "");
    }

    /**
     * 获取Controller访问路径(小写)
     * 
     * @param name
     * @return
     */
    public static String getControllerMappingX(String name) {
        return toLowerCase(getControllerMappingD(name));
    }

    /**
     * 获取Xml文件名
     * 
     * @param name
     * @return
     */
    public static String getXmlName(String name) {
        return getDapInterfaceNameD(name);
    }

    /**
     * 获取Sql文件名
     * 
     * @param name
     * @return
     */
    public static String getSqlName(String name) {
        return name;
    }

}